package main

import "fmt"

// 设计循环队列
// 设计你的循环队列实现。 循环队列是一种线性数据结构，
// 其操作表现基于 FIFO（先进先出）原则并且队尾被连接在队首之后以形成一个循环。
// 它也被称为“环形缓冲器”。

// 循环队列的一个好处是我们可以利用这个队列之前用过的空间。
// 在一个普通队列里，一旦一个队列满了，我们就不能插入下一个元素，即使在队列前面仍有空间。
// 但是使用循环队列，我们能使用这些空间去存储新的值。

// 你的实现应该支持如下操作：

// MyCircularQueue(k): 构造器，设置队列长度为 k 。
// Front: 从队首获取元素。如果队列为空，返回 -1 。
// Rear: 获取队尾元素。如果队列为空，返回 -1 。
// enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
// deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
// isEmpty(): 检查循环队列是否为空。
// isFull(): 检查循环队列是否已满。

type MyCircularQueue struct {
	Length int
	Data   []int
	// 进队操作：rear++   rear指向可插入位置，所以默认为0
	// 出队操作：front++  front表示队头，所以初始是0
	// 留一个空位
	// 队满：rear+1 == front
	// 队空: front == rear
	FrontIdx, RearIdx int
}

func Constructor(k int) MyCircularQueue {
	return MyCircularQueue{
		Length:   k+1,
		Data:     make([]int, k+1),
		FrontIdx: 0,
		RearIdx:  0,
	}
}

// 入队
func (this *MyCircularQueue) EnQueue(value int) bool {
	// 队满不可加
	if this.IsFull() {
		return false
	}
	this.Data[this.RearIdx] = value
	this.RearIdx = (this.RearIdx + 1) % this.Length
	return true
}

// 出队
func (this *MyCircularQueue) DeQueue() bool {
	// 队空则无
	if this.IsEmpty() {
		return false
	}
	this.FrontIdx = (this.FrontIdx+1)%this.Length
	return true
}

func (this *MyCircularQueue) Front() int {
	if this.IsEmpty() {
		return -1
	}
	return this.Data[this.FrontIdx]
}

func (this *MyCircularQueue) Rear() int {
	if this.IsEmpty() {
		return -1
	}
	// RearIdx指向的是插入位置，因此前一个位置才是实际的尾部
	return this.Data[(this.RearIdx-1+this.Length)%this.Length]
}

func (this *MyCircularQueue) IsEmpty() bool {

	return (this.FrontIdx)%this.Length == this.RearIdx%this.Length
}

func (this *MyCircularQueue) IsFull() bool {
	return (this.RearIdx+1)%this.Length == this.FrontIdx%this.Length
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * obj := Constructor(k);
 * param_1 := obj.EnQueue(value);
 * param_2 := obj.DeQueue();
 * param_3 := obj.Front();
 * param_4 := obj.Rear();
 * param_5 := obj.IsEmpty();
 * param_6 := obj.IsFull();
 */


 func main() {
	q := Constructor(3)
	fmt.Println(q.EnQueue(1),q)
	fmt.Println(q.EnQueue(2),q)
	fmt.Println(q.EnQueue(3),q)
	fmt.Println(q.EnQueue(4),q)
}